/**
 * 
 */
package org.abettor.smartswt.factory;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.abettor.smartswt.util.StaticProperty;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

/**
 * 生成组件对象的工厂
 * @author abettor
 *
 */
public class ShellFactory
{
	//	用于存储组件属性的 MAP
	private Map<String, WidgetPropertyParameters> properties = Collections.synchronizedMap(new HashMap<String, WidgetPropertyParameters>());
	//	用于存储组件监听器的List
	private List<WidgetListener> listeners = Collections.synchronizedList(new ArrayList<WidgetListener>());
	//	用于保存父组件信息的对象
	private Display parentDevice = null;
	private Shell parentShell = null;
	//	用于表示组件所属类的对象
	private String shellClass = null;
	//	用于表述组件风格的对象
	private int style = 0;

	/**
	 * 根据组件类型初始化组件工厂
	 * @param parentDevice 所属设备对象信息
	 * @param shellClass 组件类型（即组件类的完整名称）
	 * @param shellStyle 用于表示组件风格的字符串集合<br />
	 * 组件风格是一组由
	 * @throws IllegalAccessException 
	 * @throws NoSuchFieldException 
	 * @throws ClassNotFoundException 
	 * @throws IllegalArgumentException 
	 * @throws SecurityException 
	 */
	public ShellFactory(Display parentDevice, String shellClass, String[] shellStyle)
	throws SecurityException, IllegalArgumentException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException
	{
		this.parentDevice = parentDevice;
		this.shellClass = shellClass;

		//	获取组件风格的数值
		for(int i = 0; i < shellStyle.length; i ++)
		{
			style |= StaticProperty.getStaticIntValue(shellStyle[i]);
		}
	}

	/**
	 * 根据组件类型初始化组件工厂
	 * @param parentShell 所属父Shell对象信息
	 * @param shellClass 组件类型（即组件类的完整名称）
	 * @param shellStyle 用于表示组件风格的字符串集合<br />
	 * 组件风格是一组由
	 * @throws IllegalAccessException 
	 * @throws NoSuchFieldException 
	 * @throws ClassNotFoundException 
	 * @throws IllegalArgumentException 
	 * @throws SecurityException 
	 */
	public ShellFactory(Shell parentShell, String shellClass, String[] shellStyle)
	throws SecurityException, IllegalArgumentException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException
	{
		this.parentShell = parentShell;
		this.shellClass = shellClass;

		//	获取组件风格的数值
		for(int i = 0; i < shellStyle.length; i ++)
		{
			style |= StaticProperty.getStaticIntValue(shellStyle[i]);
		}
	}

	/**
	 * 设置组件属性
	 * @param name 属性名称
	 * @param param 属性值
	 */
	public void addProperty(String name, WidgetPropertyParameters param)
	{
		properties.put(name, param);
	}

	/**
	 * 设置组件的监听器
	 * @param listener 监听器对象
	 */
	public void addListener(WidgetListener listener)
	{
		listeners.add(listener);
	}

	/**
	 * 获取组件所属类的完整名称
	 */
	public String getShellClassName()
	{
		return shellClass;
	}

	/**
	 * 根据组件属性信息，生成一个组件对象
	 * @return 返回一个组件对象
	 * @throws ClassNotFoundException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	@SuppressWarnings("unchecked")
	public Shell newShell()
	throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException
	{
		// 用反射的方法生成组件对象
		Class[] parameterTypes = new Class[2];
		Object[] obj = new Object[2];
		if(parentShell == null)
		{
			parameterTypes[0] = Display.class;
			obj[0] = parentDevice;
		}
		else
		{
			parameterTypes[0] = Shell.class;
			obj[0] = parentShell;
		}
		parameterTypes[1] = Integer.TYPE;
		obj[1] = style;
		Class clazz = Class.forName(shellClass);
		Constructor constructor = clazz.getConstructor(parameterTypes);
		Shell shell = (Shell) constructor.newInstance(obj);

		//	用反射的方法设置组件属性
		Set<String> props = properties.keySet();
		Iterator it = props.iterator();
		while(it.hasNext())
		{
			String key = (String) it.next();
			WidgetPropertyParameters propInfo = properties.get(key);
			String setterName = "set" + key;
			Method setter = clazz.getMethod(setterName, propInfo.getClasses());
			setter.invoke(shell, propInfo.getParameters());
		}

		//	用反射的方法设置组件的监听器
		Iterator itListener = listeners.iterator();
		while(itListener.hasNext())
		{
			WidgetListener listener = (WidgetListener) itListener.next();
			String listenerName = "add" + listener.getListenerName();
			Method adder = clazz.getMethod(listenerName, listener.getListenerClasses());
			adder.invoke(shell, listener.getListenerObjects());
		}

		//	返回主窗口对象
		return shell;
	}
}
